declare var window: any

import toolboxDefine from './toolbox.xml?raw'
import InitBlocks from './BlockPackage'
import { EventEmitter } from '../../../base/events'
import { Stud } from '../../../model/Stud'


const mapKeys: any = {
    " ": "space"
}

class Scratch3 {

    public workspace : any
    public vm: any

    init(ele: any, bus: EventEmitter) {
    
        var locate = 'zh-cn'
    
        this.workspace = Blockly.inject(ele, {
            comments: true,
            disable: false,
            collapse: false,
            media: 'lib/scratch3/media/',
            readOnly: false,
            rtl: false,
            scrollbars: true,
            toolbox: toolboxDefine,
            toolboxPosition: 'start',
            horizontalLayout: false,
            //   sounds: true,
            zoom: {
                controls: true,
                wheel: true,
                startScale: 0.75,
                maxScale: 4,
                minScale: 0.25,
                scaleSpeed: 1.1
            },
            colours: {
                fieldShadow: 'rgba(255, 255, 255, 0.3)',
                dragShadowOpacity: 0.6
            }
        })
    
        // 设置语言
        this.workspace.getFlyout().setRecyclingEnabled(false)
        var xml = Blockly.Xml.workspaceToDom(this.workspace)
        Blockly.ScratchMsgs.setLocale(locate)
        Blockly.Xml.clearWorkspaceAndLoadFromXml(xml, this.workspace)
        this.workspace.getFlyout().setRecyclingEnabled(true)    
    
        // 虚拟机
        this.vm = new window.VirtualMachine()
        var stage = new VirtualMachine.Target(this.vm.runtime)
        stage.isStage = true
        this.vm.runtime.addTarget(stage)
        try{
            this.vm.setEditingTarget(stage.id)
        }catch(e) {}
        this.vm.runtime.setEditingTarget(stage)
    
        this.workspace.addChangeListener(this.vm.blockListener)
    
        this.vm.start()
    
        window.vm = this.vm
        window.stage = stage
        window.workspace = this.workspace
        window.scratch = this
    
        // 加载 blocks
        ;(async function() {
            // var data = await native.Romeos.Blockly.API.Blocks.Load() ;
            // var xml = Blockly.Xml.textToDom(data);
            // Blockly.Xml.domToWorkspace(xml, workspace);
        })() ;

        // 键盘事件
        $(document.body).keypress((e:any)=>{
            let key:string = e.key
            if(mapKeys[key])
                key = mapKeys[key]
                this.vm.runtime.startHats('event_whenkeypressed', {
                KEY_OPTION: key
            });
        })

        // part / stud 事件
        bus.on("stud.input.changed", (stud: Stud, value: number)=>{
            this.vm.runtime.startHats('be_master_event_digital_input', {
                stud: stud.info.name, value: value.toString()
            });
        })

        // 虚拟手柄事件
        this.vm.runtime.uiwidgetEvent = {
        }
        bus.on("uiwidget.rocker.input", (wid: string, x: number, y: number)=>{
            if(!this.vm.runtime.uiwidgetEvent[wid])
                this.vm.runtime.uiwidgetEvent[wid] = {x, y}
            else {
                this.vm.runtime.uiwidgetEvent[wid].x = x
                this.vm.runtime.uiwidgetEvent[wid].y = y
            }
            this.vm.runtime.startHats('be_event_ui_rocker_input', { uirocker: wid });
        })
        bus.on("uiwidget.rocker.release", (wid: string)=>{
            this.vm.runtime.uiwidgetEvent[wid].x = 0
            this.vm.runtime.uiwidgetEvent[wid].y = 0
            // 最后释放时的事件，很可能紧接着前一次事件发生，如果前一次input事件forwart未完成，本次可能丢失
            setTimeout(()=>{
                this.vm.runtime.startHats('be_event_ui_rocker_input', { uirocker: wid });
            }, 100)
        })
        bus.on("uiwidget.slider.input", (wid: string, val: number)=>{
            this.vm.runtime.uiwidgetEvent[wid] = val
            this.vm.runtime.startHats('be_event_ui_slider_input', { uislider: wid });
        })
        bus.on("uiwidget.slider.release", (wid: string, val: number)=>{
            this.vm.runtime.uiwidgetEvent[wid] = val
            // 最后释放时的事件，很可能紧接着前一次事件发生，如果前一次input事件forwart未完成，本次可能丢失
            setTimeout(()=>{
                this.vm.runtime.startHats('be_event_ui_slider_input', { uislider: wid });
            }, 100)
        })
        bus.on("uiwidget.button.down", (wid: string)=>{
            this.vm.runtime.startHats('be_event_ui_button', {
                uibutton: wid, event: 'down'
            });
        })
        bus.on("uiwidget.button.up", (wid: string)=>{
            this.vm.runtime.startHats('be_event_ui_button', {
                uibutton: wid, event: 'up'
            });
        })

        setTimeout(()=>{
            // this.unserialize('<xml xmlns="http://www.w3.org/1999/xhtml"><variables></variables><block type="event_whenkeypressed" id="M_ia@0~yNgysfk+t7]/K" x="117" y="289"><field name="KEY_OPTION">a</field><next><block type="be_pwmhub_output" id="}4nko..bm0RIfqr._||!"><field name="part">814e8cfe-d915-404a-b4b0-b1325746c549</field><field name="channel">PWM0</field><value name="value"><shadow type="math_positive_number" id="%`lNY416|jsYRY)!opKO"><field name="NUM">500</field></shadow></value></block></next></block><block type="event_whenkeypressed" id="U[@7mH|}wh?$smG!kxGN" x="93" y="464"><field name="KEY_OPTION">space</field><next><block type="be_led_setvalue" id="jh_8xe`;{jy{0oxUWJzr"><field name="part">9d4ba1c5-27a7-40ee-93f7-9a2739943e17</field><value name="value"><shadow type="math_positive_number" id="#;?;y(8(QMV7L(xT`9-/"><field name="NUM">100</field></shadow></value></block></next></block></xml>')
        },1000)

        return this.workspace
    }
    
    serialize(): string {
        var doc = Blockly.Xml.workspaceToDom(this.workspace)
        return Blockly.Xml.domToText(doc)
    }

    unserialize(data: string) {
        var xml = Blockly.Xml.textToDom(data);
        Blockly.Xml.domToWorkspace(xml, this.workspace)
    }

    generateCode(lang: string) {
        if(!Blockly.coder[lang]) {
            throw new Error("unknow language: "+lang)
        }

        Blockly.coder[lang].indent = 1
        return Blockly.coder[lang].workspaceToCode(this.workspace)
    }
}


let singleton = new Scratch3

InitBlocks(singleton)

export default singleton


// '<xml xmlns="http://www.w3.org/1999/xhtml"><variables></variables><block type="event_whenkeypressed" id="M_ia@0~yNgysfk+t7]/K" x="117" y="289"><field name="KEY_OPTION">space</field><next><block type="be_pwmhub_output" id="}4nko..bm0RIfqr._||!"><field name="part">fe8a7044-694e-404d-9109-534b68cd5d71</field><field name="channel"></field><value name="value"><shadow type="math_positive_number" id="%`lNY416|jsYRY)!opKO"><field name="NUM">500</field></shadow></value></block></next></block></xml>'